/************************************************************************
                                                                     
   Xceed Ultimate ListBox for Silverlight                                                                                                                                            
   Copyright (C) 2010 Xceed Software Inc.    
                                                                     
   This program is provided to you under the terms of the GNU General Public  
   License version 2 as published by the Free Software Foundation. 
        
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along 
   with this program, if not, write to the Free Software Foundation, Inc., 
   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

   This program can be provided to you by Xceed Software Inc. under a
   proprietary commercial license agreement for use in non-Open Source
   projects. Visit Xceed.com to find the commercial edition of 
   Xceed Ultimate ListBox for Silverlight.                                    
                                                                      
 **********************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Xceed.Silverlight.Data.Stats;

namespace Xceed.Silverlight.Data
{
  internal static class EnumeratorExtensions
  {
    #region ISyncDataSourceEnumerator Extensions

    internal static bool Move(
      this ISyncDataSourceEnumerator enumerator,
      long expectedMoveCount )
    {
      return enumerator.Move( false, expectedMoveCount );
    }

    internal static bool Move(
      this ISyncDataSourceEnumerator enumerator,
      bool approximateMove, 
      long expectedMoveCount )
    {
      Nullable<long> notUsedActualCount;
      ICollection<DataPath> notUsed;
      EstimateInt64 notUsedTotalCount;
      RelativeOffset notUsedEndPositionOffset;

      return enumerator.MoveAndFetch(
               approximateMove,
               expectedMoveCount,
               0,
               out notUsedActualCount,
               out notUsed,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    internal static bool MoveAndFetch(
      this ISyncDataSourceEnumerator enumerator,
      long expectedMoveCount,
      int expectedFetchCount,
      out Nullable<long> actualMoveCount,
      out ICollection<DataPath> fetchedItems,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      return enumerator.MoveAndFetch(
               false,
               expectedMoveCount,
               expectedFetchCount,
               out actualMoveCount,
               out fetchedItems,
               out endPositionOffset,
               out totalCount );
    }

    public static bool MoveAndFetch(
      this ISyncDataSourceEnumerator enumerator,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<DataPath> fetchedItems )
    {
      return enumerator.MoveAndFetch(
               false,
               expectedMoveCount,
               expectedFetchCount,
               out fetchedItems);
    }

    public static bool MoveAndFetch(
      this ISyncDataSourceEnumerator enumerator,
      bool approximateMove,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<DataPath> fetchedItems )
    {
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.MoveAndFetch(
               approximateMove,
               expectedMoveCount,
               expectedFetchCount,
               out notUsedActualMoveCount,
               out fetchedItems,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    #endregion ISyncDataSourceEnumerator Extensions

    #region IAsyncDataSourceEnumerator Enxtensions

    internal static IMoveAndFetchAsyncResult BeginMoveAndFetch(
      this IAsyncDataSourceEnumerator enumerator,
      long expectedMoveCount,
      int expectedFetchCount,
      AsyncCallback asyncCallback,
      object asyncState )
    {
      return enumerator.BeginMoveAndFetch(
               false,
               expectedMoveCount,
               expectedFetchCount,
               asyncCallback,
               asyncState );
    }

    internal static bool SyncMoveAndFetch( 
      this IAsyncDataSourceEnumerator enumerator,
      bool approximateMove,
      long expectedMoveCount, 
      int expectedFetchCount,
      out Nullable<long> actualMoveCount,
      out ICollection<DataPath> fetchedItems,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      IMoveAndFetchAsyncResult asyncResult = enumerator.BeginMoveAndFetch( 
                                               approximateMove,
                                               expectedMoveCount, 
                                               expectedFetchCount, 
                                               null, 
                                               null ).EnsureSyncness();
      MoveAndFetchResult<DataPath> result = enumerator.EndMoveAndFetch( asyncResult );

      fetchedItems = result.FetchedItems;
      actualMoveCount = result.ActualMoveCount;
      endPositionOffset = result.EndPositionOffset;
      totalCount = result.TotalCount;

      return result.Result;
    }

    internal static GroupFetchResult SyncFetchGroup( 
      this IAsyncDataSourceEnumerator enumerator, DataPath groupPath, 
      GroupTarget groupTarget, int expectedFetchCount )
    {
      IAsyncResult asyncResult = enumerator.BeginFetchGroup( groupPath, groupTarget, expectedFetchCount, null, null ).EnsureSyncness();
      return enumerator.EndFetchGroup( asyncResult );
    }

    internal static void SyncReset( this IAsyncDataSourceEnumerator enumerator )
    {
      IAsyncResult asyncResult = enumerator.BeginReset( null, null ).EnsureSyncness();
      enumerator.EndReset( asyncResult );
    }

    #endregion IAsyncDataSourceEnumerator Enxtensions

    #region ISyncEnumerator Extensions

    public static bool MoveToHome<T>( this ISyncEnumerator<T> enumerator )
    {
      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters(
                                                    SourcePosition.BeforeFirst,
                                                    1,
                                                    0 );

      SourcePosition notUsedEndPosition;
      ICollection<T> notUsedfetchedItems;
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.JumpMoveAndFetch(
               parameters,
               out notUsedActualMoveCount,
               out notUsedfetchedItems,
               out notUsedEndPosition,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    public static bool MoveToEnd<T>( this ISyncEnumerator<T> enumerator )
    {
      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters(
                                                    SourcePosition.AfterLast,
                                                    -1,
                                                    0 );

      SourcePosition notUsedEndPosition;
      ICollection<T> notUsedfetchedItems;
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.JumpMoveAndFetch(
               parameters,
               out notUsedActualMoveCount,
               out notUsedfetchedItems,
               out notUsedEndPosition,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    public static bool JumpMoveAndFetch<T>(
      this ISyncEnumerator<T> enumerator,
      SourcePosition startPosition,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<T> fetchedItems )
    {
      if( startPosition == null )
        throw new ArgumentNullException( "startPosition" );

      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters(
                                                startPosition,
                                                expectedMoveCount,
                                                expectedFetchCount );

      SourcePosition notUsedEndPosition;
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.JumpMoveAndFetch(
               parameters,
               out notUsedActualMoveCount,
               out fetchedItems,
               out notUsedEndPosition,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    public static bool JumpMoveAndFetch<T>(
      this ISyncEnumerator<T> enumerator,
      T startItem,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<T> fetchedItems )
    {
      return enumerator.JumpMoveAndFetch( 
        new ItemPosition( startItem ), 
        expectedMoveCount, 
        expectedFetchCount, 
        out fetchedItems );
    }

    public static ICollection<T> FetchAll<T>( this ISyncEnumerator<T> enumerator, bool reverseOrder )
    {
      ICollection<T> result;
      SourcePosition startPosition;
      int moveValue;
      int fetchValue;

      if(reverseOrder)
      {
        startPosition = SourcePosition.AfterLast;
        moveValue = -1;
        fetchValue = int.MinValue;
      }
      else
      {
        startPosition = SourcePosition.BeforeFirst;
        moveValue = 1;
        fetchValue = int.MaxValue;
      }

      enumerator.JumpMoveAndFetch(startPosition, moveValue, fetchValue, out result);

      if(result == null)
      {
        result = new List<T>(0);
      }

      return result;
    }

    #endregion ISyncEnumerator Extensions

    #region IAsyncEnumerator and IAsyncEnumerator<T> Extensions

    internal static CountResult SyncCount<T>(this IAsyncEnumerator<T> enumerator, CountParameters parameters )
    {
      IAsyncResult asyncResult = enumerator.BeginCount( parameters, null, null ).EnsureSyncness();
      return enumerator.EndCount( asyncResult );
    }

    internal static GroupCountResult SyncGroupCount<T>( this IAsyncEnumerator<T> enumerator, CountParameters parameters )
    {
      IAsyncResult asyncResult = enumerator.BeginGroupCount( parameters, null, null ).EnsureSyncness();
      return enumerator.EndGroupCount( asyncResult );
    }

    internal static StatResults SyncGetStatValues<T>( this IAsyncEnumerator<T> enumerator, StatParameters parameters )
    {
      IAsyncResult asyncResult = enumerator.BeginGetStatValues( parameters, null, null ).EnsureSyncness();
      return enumerator.EndGetStatValues( asyncResult );
    }

    internal static bool SyncJumpMoveAndFetch<T>( 
      this IAsyncEnumerator<T> enumerator,
      JumpMoveAndFetchParameters parameters,
      out Nullable<long> actualMoveCount, 
      out ICollection<T> fetchedItems, 
      out SourcePosition endPosition,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      JumpMoveAndFetchAsyncResult asyncResult = enumerator.BeginJumpMoveAndFetch(
                                                  parameters, 
                                                  null, 
                                                  null ).EnsureSyncness();
      JumpMoveAndFetchResult<T> result = enumerator.EndJumpMoveAndFetch( asyncResult );

      fetchedItems = result.FetchedItems;
      actualMoveCount = result.ActualMoveCount;
      endPosition = result.EndPositionObject;
      endPositionOffset = result.EndPositionOffset;
      totalCount = result.TotalCount;

      return result.Result;
    }

    internal static bool SyncJumpMoveAndFetch( 
      this IAsyncEnumerator enumerator,
      JumpMoveAndFetchParameters parameters,
      out Nullable<long> actualMoveCount, 
      out ICollection fetchedObjects, 
      out SourcePosition endPosition,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      JumpMoveAndFetchAsyncResult asyncResult = enumerator.BeginJumpMoveAndFetch(
                                                  parameters, 
                                                  null, 
                                                  null ).EnsureSyncness();
      JumpMoveAndFetchResult result = enumerator.EndJumpMoveAndFetch( asyncResult );

      fetchedObjects = result.FetchedObjects;
      actualMoveCount = result.ActualMoveCount;
      endPosition = result.EndPositionObject;
      endPositionOffset = result.EndPositionOffset;
      totalCount = result.TotalCount;

      return result.Result;
    }


    #endregion IAsyncEnumerator and IAsyncEnumerator<T> Extensions

    #region JumpMoveAndFetchParameters Extensions

    public static int GetFetchUnit( this JumpMoveAndFetchParameters parameters )
    {
      return DataUtils.GetUnit( parameters.ExpectedFetchCount );
    }

    public static int GetMoveUnit( this JumpMoveAndFetchParameters parameters )
    {
      return DataUtils.GetUnit( parameters.ExpectedMoveCount );
    }

    #endregion

    #region IDataHelper Extensions

    public static int CompareValues(this IDataHelper dataHelper, object firstValue, object secondValue, SortDescription sortDescription )
    {
      int compareResult = dataHelper.CompareValues( firstValue, secondValue, sortDescription.PropertyName );

      if( sortDescription.Direction == ListSortDirection.Descending )
      {
        compareResult = -compareResult;
      }

      return compareResult;
    }

    #endregion IDataHelper Extensions
  }
}
